package com.gcloud.controller.slb.provider.impl;

import java.util.UUID;

import org.openstack4j.model.network.ext.ListenerV2;
import org.openstack4j.model.network.ext.LoadBalancerV2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.gcloud.common.util.StringUtils;
import com.gcloud.controller.provider.NeutronProviderProxy;
import com.gcloud.controller.slb.async.CheckNeutronCreateloadBalancerAsync;
import com.gcloud.controller.slb.dao.ListenerDao;
import com.gcloud.controller.slb.dao.LoadBalancerDao;
import com.gcloud.controller.slb.dao.VServerGroupDao;
import com.gcloud.controller.slb.entity.Listener;
import com.gcloud.controller.slb.entity.LoadBalancer;
import com.gcloud.controller.slb.entity.VServerGroup;
import com.gcloud.controller.slb.model.DescribeLoadBalancerHTTPListenerAttributeResponse;
import com.gcloud.controller.slb.model.DescribeLoadBalancerHTTPSListenerAttributeResponse;
import com.gcloud.controller.slb.model.DescribeLoadBalancerTCPListenerAttributeResponse;
import com.gcloud.controller.slb.provider.ILoadBalancerListenerProvider;
import com.gcloud.core.exception.GCloudException;
import com.gcloud.core.simpleflow.Flow;
import com.gcloud.core.simpleflow.FlowDoneHandler;
import com.gcloud.core.simpleflow.NoRollbackFlow;
import com.gcloud.core.simpleflow.SimpleFlowChain;
import com.gcloud.header.enums.ProviderType;
import com.gcloud.header.enums.ResourceType;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class NeutronLoadBalancerListenerProvider implements ILoadBalancerListenerProvider {
	
	@Autowired
    private NeutronProviderProxy neutronProviderProxy;

    @Autowired
    private LoadBalancerDao lberDao;
    
    @Autowired
    private ListenerDao listenerDao;
    
    @Autowired
    private VServerGroupDao vServerGroupDao;
    
    public ResourceType resourceType() {
        return ResourceType.SLB_LISTENER;
    }

    public ProviderType providerType() {
        return ProviderType.NEUTRON;
    }
	
    @Override
	public String createLoadBalancerHTTPListener(String loadBalancerId, Integer listenerPort, String vServerGroupId) {
		// TODO Auto-generated method stub
    	
    	LoadBalancer lber = lberDao.getById(loadBalancerId);
    	VServerGroup vg = vServerGroupDao.getById(vServerGroupId);
    	
		SimpleFlowChain<org.openstack4j.model.network.ext.ListenerV2, String> chain = new SimpleFlowChain<>("create http listener");
        chain.then(new Flow<org.openstack4j.model.network.ext.ListenerV2>("create http listener", true) {

            @Override
            public void run(SimpleFlowChain chain, ListenerV2 data) {
                // TODO Auto-generated method stub
                ListenerV2 listener = neutronProviderProxy.createLoadBalancerHTTPListener(lber.getProviderRefId(), vg.getProviderRefId(), listenerPort);
                chain.data(listener);
                chain.next();
            }

            @Override
            public void rollback(SimpleFlowChain chain, ListenerV2 data) {
                // TODO Auto-generated method stub
                log.debug("now roll  back");
                neutronProviderProxy.deleteLoadBalancerListener(data.getId());

            }

        }).then(new NoRollbackFlow<org.openstack4j.model.network.ext.ListenerV2>("save db") {

            @Override
            public void run(SimpleFlowChain chain, ListenerV2 data) {
                // TODO Auto-generated method stub
                Listener listener = new Listener();
                listener.setId(UUID.randomUUID().toString());
                listener.setListenerPort(data.getProtocolPort());
                listener.setListenerProtocol(data.getProtocol().name());          
                listener.setVserverGroupId(vServerGroupId);
                listener.setProvider(providerType().getValue());
                listener.setProviderRefId(data.getId());
                listener.setServerCertificateId(null);
                listener.setStatus(null);
            	listener.setLoadbalancerId(loadBalancerId);
            	listener.setVserverGroupName(vg.getName());
                listenerDao.save(listener);
                chain.next();
            }

        }).done(new FlowDoneHandler<org.openstack4j.model.network.ext.ListenerV2>() {

            @Override
            public void handle(ListenerV2 data) {
                // TODO Auto-generated method stub
            	chain.setResult(data.getId());
            }

        }).start();
        if (StringUtils.isNotBlank(chain.getErrorCode())) {
            log.debug("create http listener error");
            throw new GCloudException(chain.getErrorCode());
        }
		
		return chain.data().getId();
	}
    
	@Override
	public String createLoadBalancerHTTPSListener(String loadBalancerId, Integer listenerPort, String vServerGroupId,
			String ServerCertificateId) {
		// TODO Auto-generated method stub
		LoadBalancer lber = lberDao.getById(loadBalancerId);
    	VServerGroup vg = vServerGroupDao.getById(vServerGroupId);
    	
		SimpleFlowChain<org.openstack4j.model.network.ext.ListenerV2, String> chain = new SimpleFlowChain<>("create https listener");
        chain.then(new Flow<org.openstack4j.model.network.ext.ListenerV2>("create https listener", true) {

            @Override
            public void run(SimpleFlowChain chain, ListenerV2 data) {
                // TODO Auto-generated method stub
            	ListenerV2 listener = neutronProviderProxy.createLoadBalancerHTTPSListener(lber.getProviderRefId(), vg.getProviderRefId(), listenerPort, ServerCertificateId);
                chain.data(listener);
                chain.next();
            }

            @Override
            public void rollback(SimpleFlowChain chain, ListenerV2 data) {
                // TODO Auto-generated method stub
                log.debug("now roll  back");
                neutronProviderProxy.deleteLoadBalancerListener(data.getId());

            }

        }).then(new NoRollbackFlow<org.openstack4j.model.network.ext.ListenerV2>("save db") {

            @Override
            public void run(SimpleFlowChain chain, ListenerV2 data) {
                // TODO Auto-generated method stub
                Listener listener = new Listener();
                listener.setId(UUID.randomUUID().toString());
                listener.setListenerPort(data.getProtocolPort());
                listener.setListenerProtocol(data.getProtocol().name());
                listener.setLoadbalancerId(loadBalancerId);
                listener.setVserverGroupId(vServerGroupId);
                listener.setProvider(providerType().getValue());
                listener.setProviderRefId(data.getId());
                listener.setServerCertificateId(ServerCertificateId);
                listener.setStatus(null);
            	listener.setVserverGroupName(vg.getName());
               
                listenerDao.save(listener);
                chain.next();
            }

        }).done(new FlowDoneHandler<org.openstack4j.model.network.ext.ListenerV2>() {

            @Override
            public void handle(ListenerV2 data) {
                // TODO Auto-generated method stub
            	chain.setResult(data.getId());
            }

        }).start();
        if (StringUtils.isNotBlank(chain.getErrorCode())) {
            log.debug("create https listener error");
            throw new GCloudException(chain.getErrorCode());
        }
		
		return chain.data().getId();
	}

	@Override
	public String createLoadBalancerTCPListener(String loadBalancerId, Integer listenerPort, String vServerGroupId) {
		// TODO Auto-generated method stub
		LoadBalancer lber = lberDao.getById(loadBalancerId);
    	VServerGroup vg = vServerGroupDao.getById(vServerGroupId);
    	
		SimpleFlowChain<org.openstack4j.model.network.ext.ListenerV2, String> chain = new SimpleFlowChain<>("create tcp listener");
        chain.then(new Flow<org.openstack4j.model.network.ext.ListenerV2>("create tcp listener", true) {

            @Override
            public void run(SimpleFlowChain chain, ListenerV2 data) {
                // TODO Auto-generated method stub
            	ListenerV2 listener = neutronProviderProxy.createLoadBalancerTCPListener(lber.getProviderRefId(), vg.getProviderRefId(), listenerPort);
                chain.data(listener);
                chain.next();
            }

            @Override
            public void rollback(SimpleFlowChain chain, ListenerV2 data) {
                // TODO Auto-generated method stub
                log.debug("now roll  back");
                neutronProviderProxy.deleteLoadBalancerListener(data.getId());

            }

        }).then(new NoRollbackFlow<org.openstack4j.model.network.ext.ListenerV2>("save db") {

            @Override
            public void run(SimpleFlowChain chain, ListenerV2 data) {
                // TODO Auto-generated method stub
                Listener listener = new Listener();
                listener.setId(UUID.randomUUID().toString());
                listener.setListenerPort(data.getProtocolPort());
                listener.setListenerProtocol(data.getProtocol().name());
                listener.setLoadbalancerId(loadBalancerId);
                listener.setVserverGroupId(vServerGroupId);
                listener.setProvider(providerType().getValue());
                listener.setProviderRefId(data.getId());
                listener.setServerCertificateId(null);
                listener.setStatus(null);
                listener.setVserverGroupName(vg.getName());
               
                listenerDao.save(listener);
                chain.next();
            }

        }).done(new FlowDoneHandler<org.openstack4j.model.network.ext.ListenerV2>() {

            @Override
            public void handle(ListenerV2 data) {
                // TODO Auto-generated method stub
            	chain.setResult(data.getId());
            }

        }).start();
        if (StringUtils.isNotBlank(chain.getErrorCode())) {
            log.debug("create tcp listener error");
            throw new GCloudException(chain.getErrorCode());
        }
		
		return chain.data().getId();
	}

	@Override
	public void setLoadBalancerHTTPListenerAttribute(String listenerId, String vServerGroupId) {
		// TODO Auto-generated method stub
		neutronProviderProxy.setLoadBalancerHTTPListenerAttribute(listenerId, vServerGroupId);
	}

	@Override
	public void setLoadBalancerHTTPSListenerAttribute(String listenerId, String vServerGroupId,
			String serverCertificateId) {
		// TODO Auto-generated method stub
		neutronProviderProxy.setLoadBalancerHTTPSListenerAttribute(listenerId, vServerGroupId, serverCertificateId);
	}

	@Override
	public void setLoadBalancerTCPListenerAttribute(String listenerId, String vServerGroupId) {
		// TODO Auto-generated method stub
		neutronProviderProxy.setLoadBalancerTCPListenerAttribute(listenerId, vServerGroupId);
	}

	@Override
	public void deleteLoadBalancerListener(String listenerId) {
		// TODO Auto-generated method stub
		neutronProviderProxy.deleteLoadBalancerListener(listenerId);
	}

	@Override
	public DescribeLoadBalancerHTTPListenerAttributeResponse describeLoadBalancerHTTPListenerAttribute(
			String listenerId) {
		// TODO Auto-generated method stub
		ListenerV2 listener = neutronProviderProxy.describeLoadBalancerHTTPListenerAttribute(listenerId);
		
		DescribeLoadBalancerHTTPListenerAttributeResponse response = new DescribeLoadBalancerHTTPListenerAttributeResponse();
		response.setStatus(null);
		response.setListenerPort(listener.getProtocolPort());
		response.setvServerGroupId(listener.getDefaultPoolId());
		
		return response;
	}

	@Override
	public DescribeLoadBalancerHTTPSListenerAttributeResponse describeLoadBalancerHTTPSListenerAttribute(
			String listenerId) {
		// TODO Auto-generated method stub
		ListenerV2 listener = neutronProviderProxy.describeLoadBalancerHTTPSListenerAttribute(listenerId);
		
		DescribeLoadBalancerHTTPSListenerAttributeResponse response = new DescribeLoadBalancerHTTPSListenerAttributeResponse();
		response.setStatus(null);
		response.setListenerPort(listener.getProtocolPort());
		response.setvServerGroupId(listener.getDefaultPoolId());
		response.setServerCertificateId(null);
		
		return response;
	}

	@Override
	public DescribeLoadBalancerTCPListenerAttributeResponse describeLoadBalancerTCPListenerAttribute(
			String listenerId) {
		// TODO Auto-generated method stub
		ListenerV2 listener = neutronProviderProxy.describeLoadBalancerTCPListenerAttribute(listenerId);
		
		DescribeLoadBalancerTCPListenerAttributeResponse response = new DescribeLoadBalancerTCPListenerAttributeResponse();
		response.setStatus(null);
		response.setListenerPort(listener.getProtocolPort());
		response.setvServerGroupId(listener.getDefaultPoolId());
		
		return response;
	}

}
